#include "events/common_log.h"
#include "util/common_port.h"
#include <ctype.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/route.h>
#include <linux/sockios.h>
#include <sys/sysinfo.h>
#include <netinet/tcp.h>
#include "socket_hander.h"

//#ifndef LIB_UTIL_LOG_ON
//#undef GEN_Printf
//#define GEN_Printf(l, fmt, ...)
//#endif

/*
判断连接断开的方法
法一：

当recv()返回值小于等于0时，socket连接断开。但是还需要判断 errno是否等于 EINTR，如果errno == EINTR 则说明recv函数是由于程序接收到信号后返回的，socket连接还是正常的，不应close掉socket连接。

法二：

  struct tcp_info info;
  int len=sizeof(info);
  getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
  if((info.tcpi_state==TCP_ESTABLISHED))  则说明未断开  else 断开

法三：

若使用了select等系统函数，若远端断开，则select返回1，recv返回0则断开。其他注意事项同法一。

法四：

int keepAlive = 1; // 开启keepalive属性
int keepIdle = 60; // 如该连接在60秒内没有任何数据往来,则进行探测
int keepInterval = 5; // 探测时发包的时间间隔为5 秒
int keepCount = 3; // 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.

setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));

设置后，若断开，则在使用该socket读写时立即失败，并返回ETIMEDOUT错误

法五：

自己实现一个心跳检测，一定时间内未收到自定义的心跳包则标记为已断开。

**/

SocketHander::SocketHander()
    : m_sockfd(-1)
    , m_isdead(1)
    , m_isNewCreate(1)
    , m_len(sizeof(struct sockaddr_in))
{
}

SocketHander::~SocketHander()
{
    if(m_sockfd > 0)
    {
        GEN_Printf(LOG_INFO, "close socket, %d", m_sockfd);
        shutdown(m_sockfd, SHUT_RDWR);
        ::close(m_sockfd);
    }
}

bool SocketHander::createBindSock(const char *ip, int port, bool isTcp, bool isIpv4)
{
    int on = 1, err = 0;

    memset(&m_sockaddr, 0, sizeof(sockaddr_ip));
    m_sockfd = socket(isIpv4 ? AF_INET : AF_INET6, isTcp ? SOCK_STREAM : SOCK_DGRAM, isTcp ? IPPROTO_IP : IPPROTO_UDP);
    if (m_sockfd == -1)
    {
        GEN_Printf(LOG_ERROR, "socket error, %s\n", strerror(errno));
        return -1;
    }

    if (isIpv4)
    {
        if (setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
        {
            GEN_Printf(LOG_ERROR, "setsockopt(SO_REUSEADDR) failed: %s\n", strerror(errno));
            goto err;
        }

        m_sockaddr.v4.sin_family = AF_INET;
        m_sockaddr.v4.sin_port = htons(port);
        if (ip == NULL)
        {
            m_sockaddr.v4.sin_addr.s_addr = htonl(INADDR_ANY);
        } else {
            m_sockaddr.v4.sin_addr.s_addr = inet_addr(ip);
        }

        err = bind(m_sockfd, (struct sockaddr *)&m_sockaddr.v4, sizeof(m_sockaddr.v4));
        if ( err < 0)
        {
            GEN_Printf(LOG_ERROR, "bind err, %s\n", strerror(errno));
            goto err;
        }
    } else
    {
        on = 1;
        err = setsockopt( m_sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on, (socklen_t) sizeof( on ) );
        if (err < 0)
        {
            GEN_Printf(LOG_ERROR, "setsockopt(IPV6_V6ONLY) failed: %s\n", strerror(errno));
            goto err;
        }

        m_sockaddr.v6.sin6_family	= AF_INET6;
        m_sockaddr.v6.sin6_port     = htons( (uint16_t) port );
        m_sockaddr.v6.sin6_addr     = in6addr_any;
        err = bind( m_sockfd, (struct sockaddr *)&m_sockaddr.v6, (socklen_t) sizeof( m_sockaddr.v6 ) );
        if ( err < 0)
        {
            GEN_Printf(LOG_ERROR, "ipv6 bind err, %s\n", strerror(errno));
            goto err;
        }
    }

    if (isTcp)
    {
        err = listen(m_sockfd, SOMAXCONN);
        if (err < 0)
        {
            err = listen(m_sockfd, 5);
            if (err < 0)
            {
                GEN_Printf(LOG_ERROR, "listen error%s\n", strerror(errno));
                goto err;
            }
        }
    }

    m_isdead = 0;
    m_isNewCreate = 1;
    return true;
err:
    if (m_sockfd != 0)
    {
        close(m_sockfd);
        m_sockfd = -1;
    }

    return false;
}

#define	kStringToIPAddressFlagsNone				0			//! No flags.
#define	kStringToIPAddressFlagsNoPort			( 1 << 0 )	//! Don't allow a port number to be specified.
#define	kStringToIPAddressFlagsNoPrefix			( 1 << 1 )	//! Don't allow a prefix length to be specified.
#define	kStringToIPAddressFlagsNoScope			( 1 << 2 )	//! Don't allow a scope ID to be specified.
#define	kStringToIPAddressFlagsNoIPv4Mapped		( 1 << 3 )	//! Don't allow IPv4-mapped/compatible IPv6 addresses.
#define	require_action_quiet( X, LABEL, ACTION )														\
    do 																									\
    {																									\
        if( UNLIKELY( !(X) ) ) 																			\
        {																								\
            { ACTION; }																					\
            goto LABEL;																					\
        }																								\
                                                                                                        \
    }	while( 0 )
#define	require_noerr_quiet( ERR, LABEL )																\
    do 																									\
    {																									\
        if( UNLIKELY( (ERR) != 0 ) ) 																	\
        {																								\
            goto LABEL;																					\
        }																								\
                                                                                                        \
    }	while( 0 )

#define	countof( X )						( sizeof( X ) / sizeof( X[ 0 ] ) )
#define	countof_field( TYPE, FIELD )		countof( ( (TYPE *) 0 )->FIELD )

#define kNoErr           0
#define kMalformedErr   -1
#define kRangeErr       -2
#define kUnderrunErr    -3
#define kOverrunErr     -4
#define kUnexpectedErr  -5

static int	parseIPv6Scope( const char *inStr, uint32_t *outScope, const char **outStr )
{
#if 1
    int     			err;
    char				scopeStr[ 64 ];
    char *				dst;
    char *				lim;
    int					c;
    uint32_t			scope;
    const char *		ptr;

    // Copy into a local NULL-terminated string since that is what if_nametoindex expects.

    dst = scopeStr;
    lim = dst + ( countof( scopeStr ) - 1 );
    while( ( ( c = *inStr ) != '\0' ) && ( c != ':' ) && ( c != '/' ) && ( c != ']' ) && ( dst < lim ) )
    {
        *dst++ = *inStr++;
    }
    *dst = '\0';
    SF_ASSERT( dst <= lim );

    // First try to map as a name and if that fails, treat it as a numeric scope.

    scope = if_nametoindex( scopeStr );
    if( scope == 0 )
    {
        for( ptr = scopeStr; ( ( c = *ptr ) >= '0' ) && ( c <= '9' ); ++ptr )
        {
            scope = ( scope * 10 ) + ( c - '0' );
        }
        require_action_quiet( c == '\0', exit, err = kMalformedErr );
        require_action_quiet( ( ptr != scopeStr ) && ( ( (int)( ptr - scopeStr ) ) <= 10 ), exit, err = kMalformedErr );
    }

    *outScope = scope;
    *outStr   = inStr;
    err = kNoErr;

exit:
    return( err );
#else
    OSStatus			err;
    uint32_t			scope;
    const char *		start;
    int					c;

    scope = 0;
    for( start = inStr; ( ( c = *inStr ) >= '0' ) && ( c <= '9' ); ++inStr )
    {
        scope = ( scope * 10 ) + ( c - '0' );
    }
    require_action_quiet( ( inStr != start ) && ( ( (int)( inStr - start ) ) <= 10 ), exit, err = kMalformedErr );

    *outScope = scope;
    *outStr   = inStr;
    err = kNoErr;

exit:
    return( err );
#endif
}

//	Warning: "inBuffer" may be modified even in error cases.
static int	parseIPv4Address( const char *inStr, uint8_t inBuffer[ 4 ], const char **outStr )
{
    int     		err;
    uint8_t *		dst;
    int				segments;
    int				sawDigit;
    int				c;
    int				v;

    SF_ASSERT( inBuffer );
    SF_ASSERT( outStr );

    dst		 = inBuffer;
    *dst	 = 0;
    sawDigit = 0;
    segments = 0;
    for( ; ( c = *inStr ) != '\0'; ++inStr )
    {
        if( isdigit( c ) )
        {
            v = ( *dst * 10 ) + ( c - '0' );
            require_action_quiet( v <= 255, exit, err = kRangeErr );
            *dst = (uint8_t) v;
            if( !sawDigit )
            {
                ++segments;
                require_action_quiet( segments <= 4, exit, err = kOverrunErr );
                sawDigit = 1;
            }
        }
        else if( ( c == '.' ) && sawDigit )
        {
            require_action_quiet( segments < 4, exit, err = kMalformedErr );
            *++dst = 0;
            sawDigit = 0;
        }
        else
        {
            break;
        }
    }
    require_action_quiet( segments == 4, exit, err = kUnderrunErr );

    *outStr = inStr;
    err = kNoErr;

exit:
    return( err );
}

static int	parseIPv6Address( const char *inStr, int inAllowV4Mapped, uint8_t inBuffer[ 16 ], const char **outStr )
{
    // Table to map uppercase hex characters - '0' to their numeric values.
    // 0  1  2  3  4  5  6  7  8  9  :  ;  <  =  >  ?  @  A   B   C   D   E   F
    static const uint8_t		kASCIItoHexTable[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15 };
    int                         err;
    const char *				ptr;
    uint8_t *					dst;
    uint8_t *					lim;
    uint8_t *					colonPtr;
    int							c;
    int							sawDigit;
    unsigned int				v;
    int							i;
    int							n;

    // Pre-zero the address to simplify handling of compressed addresses (e.g. "::1").

    for( i = 0; i < 16; ++i ) inBuffer[ i ] = 0;

    // Special case leading :: (e.g. "::1") to simplify processing later.

    if( *inStr == ':' )
    {
        ++inStr;
        require_action_quiet( *inStr == ':', exit, err = kMalformedErr );
    }

    // Parse the address.

    ptr		 = inStr;
    dst		 = inBuffer;
    lim		 = dst + 16;
    colonPtr = NULL;
    sawDigit = 0;
    v		 = 0;
    while( ( ( c = *inStr++ ) != '\0' ) && ( c != '%' ) && ( c != '/' ) && ( c != ']' ) )
    {
        if(   ( c >= 'a' ) && ( c <= 'f' ) ) c -= ( 'a' - 'A' );
        if( ( ( c >= '0' ) && ( c <= '9' ) ) || ( ( c >= 'A' ) && ( c <= 'F' ) ) )
        {
            c -= '0';
            SF_ASSERT( c < (int) countof( kASCIItoHexTable ) );
            v = ( v << 4 ) | kASCIItoHexTable[ c ];
            require_action_quiet( v <= 0xFFFF, exit, err = kRangeErr );
            sawDigit = 1;
            continue;
        }
        if( c == ':' )
        {
            ptr = inStr;
            if( !sawDigit )
            {
                require_action_quiet( !colonPtr, exit, err = kMalformedErr );
                colonPtr = dst;
                continue;
            }
            require_action_quiet( *inStr != '\0', exit, err = kUnderrunErr );
            require_action_quiet( ( dst + 2 ) <= lim, exit, err = kOverrunErr );
            *dst++ = (uint8_t)( ( v >> 8 ) & 0xFF );
            *dst++ = (uint8_t)(   v        & 0xFF );
            sawDigit = 0;
            v = 0;
            continue;
        }

        // Handle IPv4-mapped/compatible addresses (e.g. ::FFFF:1.2.3.4).

        if( inAllowV4Mapped && ( c == '.' ) && ( ( dst + 4 ) <= lim ) )
        {
            err = parseIPv4Address( ptr, dst, &inStr );
            require_noerr_quiet( err, exit );
            dst += 4;
            sawDigit = 0;
            ++inStr; // Increment because the code below expects the end to be at "inStr - 1".
        }
        break;
    }
    if( sawDigit )
    {
        require_action_quiet( ( dst + 2 ) <= lim, exit, err = kOverrunErr );
        *dst++ = (uint8_t)( ( v >> 8 ) & 0xFF );
        *dst++ = (uint8_t)(   v        & 0xFF );
    }
    SF_ASSERT( dst <= lim );
    if( colonPtr )
    {
        require_action_quiet( dst < lim, exit, err = kOverrunErr );
        n = (int)( dst - colonPtr );
        for( i = 1; i <= n; ++i )
        {
            lim[ -i ] = colonPtr[ n - i ];
            colonPtr[ n - i ] = 0;
        }
        dst = lim;
    }
    require_action_quiet( dst == lim, exit, err = kUnderrunErr );

    *outStr = inStr - 1;
    err = kNoErr;

exit:
    return( err );
}

static int  stringToIPv6Address(const char *inStr, int inFlags, uint8_t outIPv6[16], uint32_t *outScope, int *outPort, int *outPrefix, const char **outStr )
{
    int     		err;
    uint8_t			ipv6[ 16 ];
    int				c;
    int				hasScope;
    uint32_t		scope;
    int				hasPort;
    int				port;
    int				hasPrefix;
    int				prefix;
    int				hasBracket;
    int				i;

    SF_ASSERT(inStr);

    if( *inStr == '[' ) ++inStr; // Skip a leading bracket for []-wrapped addresses (e.g. "[::1]:80").

    // Parse the address-only part of the address (e.g. "1::1").

    err = parseIPv6Address( inStr, !( inFlags & kStringToIPAddressFlagsNoIPv4Mapped ), ipv6, &inStr );
    SF_ASSERT(0 == err);
    c = *inStr;

    // Parse the scope, port, or prefix length.

    hasScope	= 0;
    scope		= 0;
    hasPort		= 0;
    port		= 0;
    hasPrefix	= 0;
    prefix		= 0;
    hasBracket	= 0;
    for( ;; )
    {
        if( c == '%' )		// Scope (e.g. "%en0" or "%5")
        {
            require_action_quiet( !hasScope, exit, err = kMalformedErr );
            require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoScope ), exit, err = kUnexpectedErr );
            ++inStr;
            err = parseIPv6Scope( inStr, &scope, &inStr );
            require_noerr_quiet( err, exit );
            hasScope = 1;
            c = *inStr;
        }
        else if( c == ':' )	// Port (e.g. ":80")
        {
            require_action_quiet( !hasPort, exit, err = kMalformedErr );
            require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPort ), exit, err = kUnexpectedErr );
            while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) port = ( port * 10 ) + ( c - '0' );
            require_action_quiet( port <= 65535, exit, err = kRangeErr );
            hasPort = 1;
        }
        else if( c == '/' )	// Prefix Length (e.g. "/64")
        {
            require_action_quiet( !hasPrefix, exit, err = kMalformedErr );
            require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPrefix ), exit, err = kUnexpectedErr );
            while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) prefix = ( prefix * 10 ) + ( c - '0' );
            require_action_quiet( ( prefix >= 0 ) && ( prefix <= 128 ), exit, err = kRangeErr );
            hasPrefix = 1;
        }
        else if( c == ']' )
        {
            require_action_quiet( !hasBracket, exit, err = kMalformedErr );
            hasBracket = 1;
            c = *( ++inStr );
        }
        else
        {
            break;
        }
    }

    // Return the results. Only fill in scope/port/prefix results if the info was found to allow for defaults.

    if( outIPv6 )				 for( i = 0; i < 16; ++i ) outIPv6[ i ] = ipv6[ i ];
    if( outScope  && hasScope )  *outScope	= scope;
    if( outPort   && hasPort )   *outPort	= port;
    if( outPrefix && hasPrefix ) *outPrefix	= prefix;
    if( outStr )				 *outStr	= inStr;
    err = kNoErr;

exit:
    return( err );
}

bool SocketHander::createConnectSock(const char *ip, int port, bool isTcp, bool isIpv4)
{
    int	err = 0;

    memset(&m_sockaddr, 0, sizeof(sockaddr_ip));
    m_sockfd = socket(isIpv4 ? AF_INET : AF_INET6, isTcp ? SOCK_STREAM : SOCK_DGRAM, isTcp ? IPPROTO_IP : IPPROTO_UDP);
    if (m_sockfd < 0)
    {
        GEN_Printf(LOG_ERROR, "socket error, %s\n", strerror(errno));
        return -1;
    }

    if (isIpv4)
    {
        memset(&m_sockaddr.v4, 0, sizeof(m_sockaddr.v4));
        m_sockaddr.v4.sin_family   = AF_INET;
        if (ip)
        {
            const char *addr = strchr(ip, ':');
            if (addr)
            {
                char tmp[32] = {0};
                strncpy(tmp, ip, addr - ip);
                addr++;
                int t = atoi(addr);
                if (t > 0)
                {
                    GEN_Printf(LOG_INFO, "IP Port old[%d] -> new[%d]", port, t);
                    port = t;
                }
                m_sockaddr.v4.sin_addr.s_addr = inet_addr(tmp);
            } else
            {
                m_sockaddr.v4.sin_addr.s_addr = inet_addr(ip);
            }
        } else
        {
            m_sockaddr.v4.sin_addr.s_addr	= htonl(INADDR_LOOPBACK); /*inet_addr(_server_ip); */
        }
        m_sockaddr.v4.sin_port     = htons(port);
    } else
    {
        uint8_t						ipv6[ 16 ];
        uint32_t					scope = 0;

        memset(&m_sockaddr.v6, 0, sizeof(m_sockaddr.v6));
        m_sockaddr.v6.sin6_family 	= AF_INET6;

        if (ip)
        {
            err = stringToIPv6Address( ip, kStringToIPAddressFlagsNone, ipv6, &scope, &port, NULL, NULL );
            if (err)
            {
                GEN_Printf(LOG_DEBUG, "stringToIPv6Address failed. err=%d", err);
                goto exit;
            }
            m_sockaddr.v6.sin6_port		= htons( (uint16_t) port );
            memcpy( m_sockaddr.v6.sin6_addr.s6_addr, ipv6, 16 );
            m_sockaddr.v6.sin6_scope_id	= scope;
        } else
        {
            m_sockaddr.v6.sin6_port	= htons( (uint16_t) port );
            m_sockaddr.v6.sin6_addr	= in6addr_any;
        }
    }

    if (isTcp)
    {
        err = connect(m_sockfd, (struct sockaddr *)&m_sockaddr.sa, m_len);
        if (err)
        {
            GEN_Printf(LOG_DEBUG, "Connect %s:%d error, %s", ip, port, strerror(errno));
            goto exit;
        }
    }

    m_isdead = 0;
    m_isNewCreate = 1;
    return true;
exit:
    if (err && m_sockfd > 0)
    {
        close(m_sockfd);
        m_sockfd = -1;
    }
    return false;
}

bool SocketHander::setOptMulticast(const char *multiaddr, const char *interface)
{
    struct ip_mreq multicast;
    memset(&multicast, 0, sizeof(struct ip_mreq));

    SF_ASSERT(multiaddr);

    multicast.imr_multiaddr.s_addr = inet_addr(multiaddr);
    multicast.imr_interface.s_addr = interface ? inet_addr(interface)
                                               : htonl(INADDR_ANY);

    if (setsockopt(m_sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast, sizeof(multicast)) < 0)
    {
        GEN_Printf(LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP) failed! Error: %d %s", errno, strerror(errno));
        return false;
    }
    return true;
}

bool SocketHander::removeMulticast(const char *multiaddr, const char *interface)
{
    SF_ASSERT(multiaddr);
    SF_ASSERT(interface);
    struct ip_mreq multicast;
    memset(&multicast, 0, sizeof(struct ip_mreq));

    SF_ASSERT(multiaddr);

    multicast.imr_multiaddr.s_addr = inet_addr(multiaddr);
    multicast.imr_interface.s_addr = inet_addr(interface);

    if (setsockopt(m_sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &multicast, sizeof(multicast)) < 0)
    {
        GEN_Printf(LOG_ERROR, "IP_ROP_MEMBERSHIP: failed! Error: %d %s", errno, strerror(errno));
        return false;
    }
    return true;
}

bool SocketHander::setOptBlock(bool bflag)
{
    int32_t flags = fcntl(m_sockfd, F_GETFL, 0);

    if(bflag)
    {
        flags &= ~O_NONBLOCK;
        if ((fcntl(m_sockfd, F_SETFL, flags)) < 0)
        { return false;}
    } else
    {
        flags |= O_NONBLOCK;
        if (fcntl(m_sockfd, F_SETFL, flags) < 0)
        { return false;}
    }
    return true;
}

bool SocketHander::setOptBindIoDevice(const char *iface)
{
    struct ifreq netCard;

    strncpy(netCard.ifr_name, iface, IFNAMSIZ);
    if (setsockopt(m_sockfd, SOL_SOCKET, SO_BINDTODEVICE,   (char *)&netCard, sizeof(netCard)) != 0)
    {
        GEN_Printf(LOG_ERROR,"*** SO_BINDTODEVICE (%s) failed! errno is %d, %s", iface, errno, strerror(errno));
        return false;
    }

    return true;
}

bool SocketHander::isEstablished() const
{
    struct tcp_info info;
    int len = sizeof(info);
    getsockopt(m_sockfd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
    return (info.tcpi_state==TCP_ESTABLISHED) ? true : false;
}

bool SocketHander::writeData(const char *data, int len)
{
#if 1
    ssize_t numWritten;
    int     totWritten = 0;
    const char *buf = data;

    while (totWritten < len)
    {
        numWritten = send(m_sockfd, buf, len - totWritten, 0);
        if (LIKELY(numWritten > 0))
        {
            totWritten += numWritten;
            buf        += numWritten;
        } else if (numWritten == 0)
        {
            if (len != 0)
            {
                m_isdead = 1; //连接已关闭
                GEN_Printf(LOG_WARN, "Sock: %d, Write Nothing", m_sockfd);
            }
            break;
        } else
        {
            int err = errno;
            if (EINTR == err)
            {
                continue; //被中断，继续
            } else if (EWOULDBLOCK == err || EAGAIN == err)
            {
                ::usleep(3*1000);
                continue; //缓冲区满，继续
            } else
            {
                m_isdead = 1;
                GEN_Printf(LOG_ERROR, "Sock: %d, write data error, (%d, %s)", m_sockfd, err, strerror(err));
                break;
            }
        }
    }
#else
    int ret = CommonPort::sendn(m_sockfd, data, len);

    if(ret < 0)
    {
        m_isdead = 1;
        GEN_Printf(LOG_ERROR, "Sock: %d, write data error, (%d, %s)", m_sockfd, errno, strerror(errno));
    } else if(ret == 0)
    {
        GEN_Printf(LOG_DEBUG, "Sock: %d, Write Nothing: %d", m_sockfd, ret);
    }
#endif
    return !m_isdead;
}

bool SocketHander::readData(char *data, int len)
{
#if 1
    ssize_t numRead = 0;
    int     totRead = 0;
    int     err  = 0;
    char    *buf = data;

    while (totRead < len)
    {
        numRead = recv(m_sockfd, buf, len - totRead, 0);

        if (LIKELY(numRead > 0))
        {
            totRead += numRead;
            buf     += numRead;
        } else if (numRead == 0)
        {
            if (len != 0)
            {
                m_isdead = 1; //连接已关闭
                GEN_Printf(LOG_ERROR, "Sock: %d, Read 0, the peer has performed an orderly shutdown", m_sockfd);
            }
            break;
        } else
        {
            err = errno;
            if (EINTR == err)
            {
                continue; // 被中断，继续
            } else if (EAGAIN == err || EWOULDBLOCK == err)
            {
                ::usleep(3*1000);
                continue; //缓冲区满，继续
            } else
            {
                m_isdead = 1;
                GEN_Printf(LOG_ERROR, "Sock: %d, read data error, (%d, %s)", m_sockfd, err, strerror(err));
                break;
            }
        }
    }
#else
    errno = 0;
    int ret = CommonPort::recvn(m_sockfd, data, len);
    if(ret < 0)
    {
        m_isdead = 1;
        GEN_Printf(LOG_ERROR, "Sock: %d, Read error, (%d, %s)", m_sockfd, errno, strerror(errno));
    }else if(ret == 0)
    {        
        m_isdead = 1;
        GEN_Printf(LOG_ERROR, "Sock: %d, Read 0, the peer has performed an orderly shutdown", m_sockfd);
    }
#endif
    return !m_isdead;
}

int SocketHander::readOne(char *data, int len)
{
    int ret = ::recv(m_sockfd, data, len, 0);
    if (LIKELY(ret > 0))
    {
        return ret;
    } else if (0 == ret)
    {
        if (len != 0)
        {
            ret = -1;
            m_isdead = 1; //连接已关闭
            GEN_Printf(LOG_ERROR, "Sock: %d, Read 0, the peer has performed an orderly shutdown", m_sockfd);
        }
    } else
    {
        int err = errno;
        if (EINTR == err || EAGAIN == err)
        {
            ret = 0;
        } else
        {
            m_isdead = 1;
            GEN_Printf(LOG_ERROR, "Sock: %d, Read error, (%d, %s)", m_sockfd, err, strerror(err));
        }
    }

    return ret;
}

void SocketHander::closeSock()
{
    if(m_sockfd > 0)
    {
        GEN_Printf(LOG_INFO, "close socket, %d", m_sockfd);
        shutdown(m_sockfd, SHUT_RDWR);
        ::close(m_sockfd);
        m_sockfd = -1;
        m_isdead = 1;
    }
}

bool SocketHander::selectSock(int ms)
{
    int     res;
    fd_set  rdfdset;
    struct timeval timeout = {ms / 1000, (ms % 1000) * 1000};

restart:
    FD_ZERO(&rdfdset);
    FD_SET(m_sockfd, &rdfdset);
    res = select(m_sockfd + 1, &rdfdset, NULL, NULL, &timeout);
    if (UNLIKELY(res < 0))
    {
        if(errno == EINTR ) goto restart;
        GEN_Printf(LOG_ERROR, "Failed to select. (%d, %s)", errno, strerror(errno));
        m_isdead = 1;
        return false;
    }else if (0 == res)
    {
        return false;
    }else
    {
        return true;
    }
}

bool SocketHander::selectWRSock(int ms)
{
    int     res;
    fd_set  rdfdset;
    struct timeval timeout = {ms / 1000, (ms % 1000) * 1000};

restart:
    FD_ZERO(&rdfdset);
    FD_SET(m_sockfd, &rdfdset);
    res = select(m_sockfd + 1, NULL, &rdfdset, NULL, &timeout);
    if (UNLIKELY(res < 0))
    {
        if(errno == EINTR ) goto restart;
        GEN_Printf(LOG_ERROR, "Failed to select. (%d, %s)", errno, strerror(errno));
        m_isdead = 1;
        return false;
    }else if (0 == res)
    {
        return false;
    }else
    {
        return true;
    }
}

const SocketHander::sockaddr_ip &SocketHander::getLocalAddr()
{
    m_len = sizeof(m_sockaddr);
    getsockname(m_sockfd, (struct sockaddr *)&m_sockaddr.sa, &m_len);

    //char* pTmp = inet_ntoa(m_sockaddr.v4.sin_addr);
    //GEN_Printf(LOG_DEBUG, "local: %s", pTmp);
    return m_sockaddr;
}

const char *SocketHander::getLocalAddr_c()
{
    m_len = sizeof(m_sockaddr);
    getsockname(m_sockfd, (struct sockaddr *)&m_sockaddr.sa, &m_len);

    return inet_ntoa(m_sockaddr.v4.sin_addr);
}

const SocketHander::sockaddr_ip &SocketHander::getRemoteAddr()
{
    m_len = sizeof(m_sockaddr);
    getpeername(m_sockfd, (struct sockaddr *)&m_sockaddr.sa, &m_len);

    //char* pTmp = inet_ntoa(m_sockaddr.v4.sin_addr);
    //GEN_Printf(LOG_DEBUG, "remote: %s", pTmp);
    return m_sockaddr;
}

const char *SocketHander::getRemoteAddr_c()
{
    m_len = sizeof(m_sockaddr);
    getpeername(m_sockfd, (struct sockaddr *)&m_sockaddr.sa, &m_len);

    return inet_ntoa(m_sockaddr.v4.sin_addr);;
}

bool SocketHander::acceptSock(int sock_fd)
{
    int new_fd = ::accept(sock_fd, sockAddr(), sockLen());
    if (LIKELY(new_fd > 0))
    {
        m_sockfd = new_fd;
        m_isdead = 0;
        m_isNewCreate = 1;
        return true;
    }
    return false;
}

bool SocketHander::listenSock(int conns)
{
    int b_reuse = 1;
    setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));

    if (::listen(m_sockfd, conns/*SOMAXCONN*/) < 0)
    {
        GEN_Printf(LOG_ERROR, "listen failed, %s", strerror(errno));
        return false;
    }
    return true;
}

bool SocketHander::setSock(int fd)
{
    if (LIKELY(fd > 0))
    {
        m_sockfd = fd;
        m_isdead = 0;
        m_isNewCreate = 1;
        return true;
    }
    return false;
}

void SocketHander::moveSock()
{
    m_sockfd = -1;
    m_isdead = 1;
}

void SocketHander::copy(SocketHander *that)
{
    m_sockfd      = that->m_sockfd;
    m_isdead      = that->m_isdead;
    m_isNewCreate = that->m_isNewCreate;
    m_len         = that->m_len;
    m_sockaddr    = that->m_sockaddr;
}

